package com.jietong.rfid.uhf.mode;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.jietong.rfid.uhf.callback.CallBack;
import com.jietong.rfid.uhf.command.R2000Command;
import com.jietong.rfid.util.AntStruct;
import com.jietong.rfid.util.BitOperation;
import com.jietong.rfid.util.DataConvert;
import com.jietong.rfid.util.Regex;

public class R2000DataParseManage extends BasePackage {
	
	private int headCount = 0;
	private int dataCount = 0;
	private int receLength = 0;
	private byte sendCmd;
	private byte receiveCmd;
	private byte seq;
	private byte[] startcode = new byte[2];
	private byte len[] = new byte[2];
	private byte data[] = new byte[100];
	private byte bcc;
	private ByteBuffer receiveBuf = ByteBuffer.allocate(500);
	private ByteBuffer receiveLength = ByteBuffer.allocate(1);
	private Map<Byte,ReceiveData> mapData = new HashMap<Byte, ReceiveData>();
	protected String communicationMode = "";

	protected byte[] getSendCMD(int length) {
		byte[] sendData = new byte[7 + length];
		sendData[0] = startcode[0];
		sendData[1] = startcode[1];
		sendData[2] = sendCmd;
		sendData[3] = seq;
		sendData[4] = len[0];
		sendData[5] = len[1];
		int count = 0;
		int i = 6;
		if (length > 0) {
			for (; i < sendData.length && count < length; i++) {
				sendData[i] = data[count];
				count++;
			}
		}
		sendData[i] = bcc;
		return sendData;
	}
	
	protected boolean sendData(byte cmd, byte[] sendBuf, int bufsize) {
		startcode[0] = R2000Command.NET_START_CODE1;
		startcode[1] = R2000Command.NET_START_CODE2;
		this.sendCmd = cmd;
		seq = 0;
		len[0] = (byte) bufsize;
		len[1] = (byte) (bufsize / 256);
		bcc = 0;
		if (bufsize > 0) {
			data = Arrays.copyOf(sendBuf, bufsize + 1);
			bcc = checkSum(sendBuf, bufsize);
		} else {
			data = Arrays.copyOf(data, 1);
		}
		data[bufsize] = bcc;
		byte[] data = getSendCMD(bufsize);
		boolean size = false;
		if (null != serialPort) {
			size = comSendData(serialPort, data);
		}
		return size;
	}
	
	protected void readData() {
		byte[] receiveVal = null;
		if (null != serialPort) {
			receiveVal = comReceiveData(serialPort);
		}
		if (null == receiveVal) {
			return;
		}
		deviceTransBufferV2(receiveVal, null);
	}

	protected boolean trandPackageV2(byte data) {
		if (headCount < R2000Command.HEAD_LENGTH) {
			switch (headCount) {
			case 0:
				if (data == R2000Command.NET_START_CODE1) {
					headCount++;
				} else {
					headCount = 0;
				}
				break;
			case 1:
				if (data == R2000Command.NET_START_CODE2) {
					headCount++;
				} else {
					headCount = 0;
				}
				break;
			case 2:
				receiveCmd = data;
				headCount++;
				break;
			case 3:
				seq = data;
				headCount++;
				break;
			case 4:
				receLength = DataConvert.byteToInt(data);
				len[0] = data;
				receiveBuf.clear();
				receiveLength.clear();
				receiveLength.put(data);
				headCount++;
				break;
			case 5:
				len[1] = data;
				headCount++;
				break;
			}
		} else if (dataCount < receLength) {
			receiveBuf.put(data);
			dataCount++;
		} else {
			byte[] bufData = Arrays.copyOf(receiveBuf.array(), receLength);
			bcc = checkSum(bufData, receiveLength.array()[0]);
			if (bcc == data) {
				headCount = 0;
				dataCount = 0;
				return true;
			} else {
				headCount = 0;
				dataCount = 0;
				return false;
			}
		}
		return false;
	}
	
	private byte checkSum(byte[] startcode, int length) {
		byte sum = 0x00;
		for (int i = 0; i < length; ++i) {
			sum ^= startcode[i];
		}
		return sum;
	}
	
	private void readCardInfo(int length,byte[] readData,Map<String, String> EpcData,CallBack.R2000 callBack){
		if (length > 1) {
			EpcData = filterEpcRssiAndAnt(readData);
			String epc = EpcData.get("EPC");
			String rssi = EpcData.get("RSSI");
			String ant = EpcData.get("ANT");
			String deviceNo = EpcData.get("DeviceNo");
			String direction = EpcData.get("Direction");
			String communicationMode = EpcData.get("communicationMode");
			callBack.readData(epc,rssi,ant,deviceNo,direction,communicationMode);
		}
	}
	
	private void readOnceCardInfo(int length,byte[] readData,Map<String, String> EpcData,CallBack.R2000 callBack){
		if (length > 1) {
			EpcData = filterEpcAndAnt(readData);
			callBack.readData(EpcData.get("EPC"), null, EpcData.get("ANT"), null, null, EpcData.get("communicationMode"));
		}
	}
	
	private Map<String, String> filterEpcRssiAndAnt(byte[] readData) {
		Map<String, String> filterData = new HashMap<String, String>();
		filterData = new HashMap<String, String>();
		byte[] dataStorage = new byte[5];

		String ant = ""; // dataStorage[0]
		String rssi = "";// dataStorage[1]
		String deviceNo = "";// dataStorage[2,3]
		String direction = "";// dataStorage[4]

		String data = DataConvert.bytesToHexString(readData);
		//System.out.println("EPC " + data);

		System.arraycopy(readData, 0, dataStorage, 0, 1);
		int EPCLength = DataConvert.byteToInt(dataStorage[0]);// temporary
																// storage
		System.arraycopy(readData, 1, dataStorage, 0, 1);
		boolean[] type = BitOperation.byteToBooleans(dataStorage[0]);// temporary
																		// storage
		int index = 0;
		if (type[0]) { // has antenna
			System.arraycopy(readData, EPCLength + 2 + index, dataStorage, 0, 1);
			ant = String.valueOf(DataConvert.byteToInt(dataStorage[0]));
			index++;
		}
		if (type[1]) {// has rssi
			System.arraycopy(readData, EPCLength + 2 + index, dataStorage, 1, 1);
			rssi = String.valueOf(DataConvert.byteToInt(dataStorage[1]));
			index++;
		}
		if (type[2]) {// has deviceNo
			System.arraycopy(readData, EPCLength + 2 + index, dataStorage, 2, 2);
			int devNo = 0;
			devNo |= DataConvert.byteToInt(dataStorage[2]) << 8;
			devNo |= DataConvert.byteToInt(dataStorage[3]);
			deviceNo = String.valueOf(devNo);
			index += 2;
		}
		if (type[3]) { // has trigger antenna
			System.arraycopy(readData, EPCLength + 2 + index, dataStorage, 4, 1);
			direction = String.valueOf(DataConvert.byteToInt(dataStorage[4]));
			index++;
		}
		byte[] epcData = new byte[EPCLength];
		System.arraycopy(readData, 2, epcData, 0, EPCLength);
		String EPC = DataConvert.bytesToHexString(epcData);

		filterData.put("EPC", EPC); // EPC
		filterData.put("ANT", ant); // Antenna
		filterData.put("RSSI", rssi);// RSSI
		filterData.put("DeviceNo", deviceNo);// deviceNo
		filterData.put("Direction", direction);// direction
		filterData.put("communicationMode", communicationMode);
		return filterData;
	}
	
	private Map<String, String> filterEpcAndAnt(byte[] readData) {
		Map<String, String> map = null;
		if (readData.length > 10) {
			map = new HashMap<String, String>();
			String total = DataConvert.bytesToHexString(readData);
			String antten = total.substring(total.length() - 2, total.length());
			int ant = Integer.parseInt(antten, 16);
			String EPC = DataConvert.bytesToHexString(Arrays.copyOf(readData,12));
			map.put("EPC", EPC);
			map.put("ANT", String.valueOf(ant + 1));
			map.put("communicationMode", communicationMode);
		}
		return map;
	}

	protected byte[] setAntAllChannel(AntStruct antStruct) {
		if (channel == 4) {
			return setAnt4(antStruct);
		} else if (channel == 32) {
			return setAnt32(antStruct);
		} else if (channel == 16) {
			return setAnt16(antStruct);
		}
		return null;
	}

	private byte[] setAnt4(AntStruct antStruct) {
		ByteBuffer sendAnt = ByteBuffer.allocate(36);
		byte[] antenner = new byte[4];
		for (int i = 0; i < antenner.length; i++) {
			antenner[i] = antStruct.enable[i];
		}
		sendAnt.put(antenner);
		byte[] time = new byte[4];
		for (int i = 0; i < time.length; i++) {
			time = DataConvert.intToByteArray(antStruct.dwellTime[i]);
			sendAnt.put(time);
		}
		byte[] power = new byte[4];
		for (int i = 0; i < power.length; i++) {
			power = DataConvert.intToByteArray(antStruct.power[i]);
			sendAnt.put(power);
		}
		return sendAnt.array();
	}
	
	protected boolean getCallBack(ByteBuffer buffer,IntBuffer bufferLength,byte cmd,int timeOut) {
		long end;
		long temp = 0;
		boolean flag = false;
		long start = System.currentTimeMillis();
		do {
			if (mapData.containsKey(cmd)) {
				buffer.put(mapData.get(cmd).getData());
				bufferLength.put(mapData.get(cmd).getLength());
				flag = true;
				mapData.remove(cmd);
				break;
			}
			end = System.currentTimeMillis();
			temp = end - start;
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} while (temp < timeOut);
		end = System.currentTimeMillis();
		//System.out.println("count time " + (end - start));
		return flag;
	}
	
     protected void deviceTransBufferV2(byte[] buffer, CallBack.R2000 callBack) {
		Map<String, String> EpcData = null;
		for (int i = 0; i < buffer.length; i++) {
			if (trandPackageV2(buffer[i])) {
				int length = DataConvert.byteToInt(receiveLength.array()[0]);
				byte[] readData = Arrays.copyOf(receiveBuf.array(), length);
				switch (receiveCmd) {
				case R2000Command.UHF_INV_ONCE:
				case R2000Command.UHF_INV_MULTIPLY_BEGIN:
				case R2000Command.UHF_INV_ONCE_V2:
				case R2000Command.UHF_INV_MULTIPLY_BEGIN_V2:
				case R2000Command.UHF_INV_MULTIPLY_END_V2:
				case R2000Command.UHF_GET_VERSION:
				case R2000Command.UHF_GET_DEVICE_NO:
				case R2000Command.UHF_SET_DEVICE_NO:
				case R2000Command.UHF_SET_BUZZ:
				case R2000Command.UHF_GET_BUZZ:
				case R2000Command.UHF_GET_MODE:
				case R2000Command.UHF_SET_MODE:
				case R2000Command.UHF_SET_TRIGGER_TIME:
				case R2000Command.UHF_GET_TRIGGER_TIME:
				case R2000Command.UHF_SET_OUTPUT:
				case R2000Command.UHF_GET_OUTPUT:
				case R2000Command.UHF_SET_TRIGGER_ALARM:
				case R2000Command.UHF_GET_ANT_STATE:
				case R2000Command.UHF_READ_TAG_DATA:
				case R2000Command.UHF_WRITE_TAG_DATA:
				case R2000Command.UHF_SET_DO_STATE:
				case R2000Command.UHF_GET_DI_STATE:
				case R2000Command.UHF_LOCK_TAG:
				case R2000Command.UHF_GET_ANT_CONFIG:
				case R2000Command.UHF_SET_ANT_CONFIG:
				case R2000Command.UHF_GET_FREQUENCY:
				case R2000Command.UHF_SET_FREQUENCY:
				case R2000Command.UHF_GET_INV_PATTERN_CONFIG:
				case R2000Command.UHF_SET_INV_PATTERN_CONFIG:
				case R2000Command.UHF_GET_INV_OUTPUT_DATA:
				case R2000Command.UHF_SET_INV_OUTPUT_DATA:
				case R2000Command.UHF_FACTORY_DATA_RESET:
				case R2000Command.UHF_GET_TAG_FILTER:
				case R2000Command.UHF_SET_TAG_FILTER:
					if(receiveCmd == R2000Command.UHF_INV_MULTIPLY_BEGIN_V2 || receiveCmd == R2000Command.UHF_INV_ONCE_V2){
						readCardInfo(length, readData, EpcData, callBack);
					}else if(receiveCmd == R2000Command.UHF_INV_MULTIPLY_BEGIN  || receiveCmd == R2000Command.UHF_INV_ONCE){
						readOnceCardInfo(length, readData, EpcData, callBack);
					}
					mapData.put(receiveCmd, new ReceiveData(receiveCmd, length, readData,communicationMode));
					break;
				default:
					break;
				}
			}
		}
	}
	
     protected List<Boolean> frequencyPoint(byte[] result) {
 		List<Boolean> total = new ArrayList<Boolean>();
 		int index = 0;
 		for (int i = 0; i < 7; i++) {
 			boolean[] point = BitOperation.byteToBooleans(result[i + 1]);
 			for (int j = point.length - 1; j >= 0; j--) {
 				if (index == 50) {
 					break;
 				}
 				total.add(point[j]);
 				index++;
 			}
 		}
 		return total;
 	}
     
     protected double frequencyFixed(byte[] result) {
 		int[] frequency = new int[3];
 		for (int i = 0; i < frequency.length; i++) {
 			frequency[i] = DataConvert.byteToInt(result[i + 1]);
 		}
 		double frequencyFixed = frequency[0] * 256 * 256 + frequency[1] * 256 + frequency[2];
 		return frequencyFixed / 1000;
 	}

     protected byte[] frequencyFixed(int result) {
 		byte[] frequency = new byte[3];
 		frequency[0] = (byte) (result >> 16);
 		frequency[1] = (byte) ((result >> 8) % 256);
 		frequency[2] = (byte) (result % 256);
 		return frequency;
 	}

	protected byte[] frequencyHoppingFilter(boolean[] frequencyHopping) {
		boolean[] frequency = new boolean[50];
		for (int i = 0; i < frequencyHopping.length; i++) {
			frequency[i] = frequencyHopping[i];
		}
		byte[] value = new byte[7];
		value[0] = BitOperation.booleansReversalToByte(frequency, 0, 8);
		value[1] = BitOperation.booleansReversalToByte(frequency, 8, 16);
		value[2] = BitOperation.booleansReversalToByte(frequency, 16, 24);
		value[3] = BitOperation.booleansReversalToByte(frequency, 24, 32);
		value[4] = BitOperation.booleansReversalToByte(frequency, 32, 40);
		value[5] = BitOperation.booleansReversalToByte(frequency, 40, 48);
		value[6] = BitOperation.booleansReversalToByte(frequency, 48, 50);
		return value;
	}
	
	protected boolean filterOperationAreaData(byte bank, byte begin, byte size){
		if (bank == 0) {// Reserve
			if (begin + size > 4) {
				return false;
			}
		} else if (bank == 1) { // EPC
			if (begin + size > 8) {
				return false;
			}
		} else if (bank == 2) { // TID
			if (begin + size > 6) {
				return false;
			}
		} else if (bank == 3) { // User
			if (begin + size > 32) {
				return false;
			}
		} else { 
			return false;
		}
		return true;
	}
	
	protected void setVersion(String version) {
		String getChannel = version.substring(version.length() - 2, version.length());
		if(Regex.isDecNumber(getChannel)){
			this.channel = Integer.parseInt(getChannel);
			if(this.channel < 7){
				this.channel = 4;
			}
		}
	}

	public byte[] reverse32Ant(byte[] ant, int start, int end,int start2, int end2) {
		byte[] antten = new byte[8];
		int count = 0;
		for (int i = end; i >= start; i--) {
			antten[count] = ant[i];
			count++;
		}
		for (int i = end2; i >= start2; i--) {
			antten[count] = ant[i];
			count++;
		}
		return antten;
	}

	public byte[] setAnt32(AntStruct antStruct) {
		ByteBuffer sendAnt = ByteBuffer.allocate(36);
		byte[] antenner = new byte[4];
		
		byte[] ant1 = reverse32Ant(antStruct.enable, 16, 19, 0, 3);
		byte[] ant2 = reverse32Ant(antStruct.enable, 20, 23, 4, 7);
		byte[] ant3 = reverse32Ant(antStruct.enable, 24, 27, 8, 11);
		byte[] ant4 = reverse32Ant(antStruct.enable, 28, 31, 12, 15);
		
		antenner[0] = BitOperation.bytesToByte(ant1);
		antenner[1] = BitOperation.bytesToByte(ant2);
		antenner[2] = BitOperation.bytesToByte(ant3);
		antenner[3] = BitOperation.bytesToByte(ant4);

		byte[] time = new byte[4];
		time = DataConvert.intToByteArray(antStruct.dwellTime[0]);
		byte[] power = new byte[4];
		power = DataConvert.intToByteArray(antStruct.power[0] * 10);

		sendAnt.put(antenner);
		for (int i = 0; i < power.length; i++) {
			sendAnt.put(time);
		}
		for (int i = 0; i < power.length; i++) {
			sendAnt.put(power);
		}
		return sendAnt.array();
	}
	
	public AntStruct antenna32Channel(byte[] buffer,int channel) {
		AntStruct struct = new AntStruct(channel);
		for (int i = 0; i < 4; i++) {
			int result = DataConvert.byteToInt(buffer[i]);
			for (int j = 0; j < 4; j++) {
				struct.enable[i * 4 + j] = (byte) ((result & (byte) Math.pow(0x02, j)) >> j);
			}
		}
		byte[] time = new byte[4];
		System.arraycopy(buffer, 4 + 3 * 4, time, 0, 4);
		struct.dwellTime[0] = DataConvert.bytesToInt(time, 0);

		byte[] power = new byte[4];
		System.arraycopy(buffer, 4 + 7 * 4, power, 0, 4);
		struct.power[0] = DataConvert.bytesToInt(power, 0) / 10;

		if (channel == 16) {
			return struct;
		}
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				int result = DataConvert.byteToInt(buffer[i]);
				struct.enable[i * 4 + j + 16] = (byte) ((result & (byte) Math.pow(0x02, j + 4)) >> j + 4);
			}
		}
		return struct;
	}
		
	public byte[] reverse16Ant(byte[] ant, int start, int end) {
		byte[] antten = new byte[8];
		int count = 4;
		for (int i = end; i >= start; i--) {
			antten[count] = ant[i];
			count++;
		}
		return antten;
	}
		
	public byte[] setAnt16(AntStruct antStruct) {
		ByteBuffer sendAnt = ByteBuffer.allocate(36);
		byte[] antenner = new byte[4];
		
		byte[] ant1 = reverse16Ant(antStruct.enable, 0, 3);
		byte[] ant2 = reverse16Ant(antStruct.enable, 4, 7);
		byte[] ant3 = reverse16Ant(antStruct.enable, 8, 11);
		byte[] ant4 = reverse16Ant(antStruct.enable, 12, 15);
		
		antenner[0] = BitOperation.bytesToByte(ant1);
		antenner[1] = BitOperation.bytesToByte(ant2);
		antenner[2] = BitOperation.bytesToByte(ant3);
		antenner[3] = BitOperation.bytesToByte(ant4);

		byte[] time = new byte[4];
		time = DataConvert.intToByteArray(antStruct.dwellTime[0]);
		
		byte[] power = new byte[4];
		power = DataConvert.intToByteArray(antStruct.power[0] * 10);

		sendAnt.put(antenner);
		for (int i = 0; i < power.length; i++) {
			sendAnt.put(time);
		}
		for (int i = 0; i < power.length; i++) {
			sendAnt.put(power);
		}
		return sendAnt.array();
	}
		
	public AntStruct antenna4Channel(byte[] buffer,int channel) {
		AntStruct struct = new AntStruct(channel);
		for (int i = 0; i < 4; i++) {
			int result = DataConvert.byteToInt(buffer[i]);
			struct.enable[i] = (byte) result;
		}
		byte[] time = new byte[4];
		for (int i = 0; i < time.length; i++) {
			System.arraycopy(buffer, 4 + i * 4, time, 0, 4);
			struct.dwellTime[i] = DataConvert.bytesToInt(time, 0);
		}
		byte[] power = new byte[4];
		for (int i = 0; i < power.length; i++) {
			System.arraycopy(buffer, 4 + (4 + i) * 4, power, 0, 4);
			struct.power[i] = DataConvert.bytesToInt(power, 0);
		}
		return struct;
	}
}